package formulation;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;

import es.deusto.ingenieria.is.search.algorithms.Node;
import es.deusto.ingenieria.is.search.algorithms.SearchMethod;
import es.deusto.ingenieria.is.search.formulation.Problem;
import es.deusto.ingenieria.is.search.formulation.State;

public class HanoiTowerProblem extends Problem
{	
	
	public HanoiTowerProblem(int numSoportes, int numDiscos, int posicionSoporteInicial, int posicionSoporteFinal)
	{
		super();
		this.createInitialState(numSoportes, numDiscos, posicionSoporteInicial, posicionSoporteFinal);
		this.createFinalStates(numSoportes, numDiscos, posicionSoporteInicial, posicionSoporteFinal);
		this.createOperators(numSoportes);
	}
	
	private void createInitialState(int numSoportes, int numDiscos, int posicionSoporteInicial, int posicionSoporteFinal)
	{
		Environment environment = new Environment(numSoportes, numDiscos, posicionSoporteInicial);
		environment.setSoporteInicial(posicionSoporteInicial);
		environment.setSoporteFinal(posicionSoporteFinal);
		this.addInitialState(environment);
	}
	
	private void createFinalStates(int numSoportes, int numDiscos, int posicionSoporteInicial, int posicionSoporteFinal) 
	{
//		for (int i = 1; i <= numSoportes; i++)
//		{
//			if (i != posicionSoporteInicial)
//			{
//				this.addFinalState(new Environment(numSoportes, numDiscos, i));
//			}
//		}
		
		Environment environment = new Environment(numSoportes, numDiscos, posicionSoporteFinal);
		environment.setSoporteInicial(posicionSoporteInicial);
		environment.setSoporteFinal(posicionSoporteFinal);
		this.addFinalState(environment);
	}
	
	@Override
	public boolean isFinalState(State state)
	{
//		for (int i = 0; i < this.getFinalStates().size(); i++)
//		{	
//			if (((Environment)state).equals(this.getFinalStates().get(i)))
//			{
//				return true;
//			}
//		}
//
//		return false;
		
		return ((Environment)state).equals(this.getFinalStates().get(0));
	}
	
	private void createOperators(int numSoportes) 
	{
		for (int i = 1; i <= numSoportes; i++)
		{
			for (int j = 1; j <= numSoportes; j++)
			{
				if (i != j)
				{
					this.addOperator(new MoverDisco(i, j));
				}
			}
		}
	}
	
	public void mostrarTiempo(long horaIniM, long horaFinM)
	{
		long mins = 0;
		long secs = 0;
		long mils = horaFinM - horaIniM;
		while (mils >= 1000)
		{
			secs = secs + 1;
			mils = mils - 1000;
			while (secs >= 60)
			{
				mins = mins + 1;
				secs = secs - 60;
			}
		}
		System.out.println("Tiempo total: " + mins + " minutos, " + secs + " segundos, " + mils + " milesimas");
	}
	
	public void solve(SearchMethod searchMethod) 
	{		
		SimpleDateFormat formatter = new SimpleDateFormat("hh:mm:ss.SSS");
		long horaIniM = GregorianCalendar.getInstance().getTimeInMillis();
		Date horaIni = GregorianCalendar.getInstance().getTime();
		System.out.println("* Start '" + searchMethod.getClass().getSimpleName() + "' (" + formatter.format(GregorianCalendar.getInstance().getTime()) + ")");
		Node finalNode = searchMethod.search(this, this.getInitialStates().get(0));
		System.out.println("* End   '" + searchMethod.getClass().getSimpleName() + "' (" + formatter.format(GregorianCalendar.getInstance().getTime()) + ")");		
		long horaFinM = GregorianCalendar.getInstance().getTimeInMillis();
		Date horaFin = GregorianCalendar.getInstance().getTime();
		if (finalNode != null)
		{
			System.out.println("\n- :-) Solution found!");
			System.out.println("Hora Inicio: " + formatter.format(horaIni));
			System.out.println("Hora Final: " + formatter.format(horaFin));
			this.mostrarTiempo(horaIniM, horaFinM);
			System.out.println("Coste: " + finalNode.getDepth() + " movimientos");
			List<String> operators = new ArrayList<String>();
			searchMethod.solutionPath(finalNode, operators);
			searchMethod.createSolutionLog(operators);
		} 
		else
		{
			System.out.println("\n- :-( Unable to find the solution!");
		}
	}
	
//	public static void main(String[] args)
//	{
//		HanoiTowerProblem htp = new HanoiTowerProblem(3, 4, 1, 3);
//		System.out.println("Estados Iniciales: " + htp.getInitialStates().toString());
//		System.out.println();
//		System.out.println("Estados Finales: " + htp.getFinalStates().toString());
//		System.out.println();
//		System.out.println("Operadores: " + htp.getOperators().toString());
//		System.out.println();
//		
//		Environment env = (Environment) htp.getFinalStates().get(0);
//		System.out.println("Estado a comprobar: " + env.toString());
//		System.out.println("IsFinalState: " + htp.isFinalState((Environment)env.clone()));
//		
//		System.out.println();
//		
//		env = (Environment) ((Environment) htp.getFinalStates().get(0)).clone();
//		env.getSoportes().get(1).getDiscos().pop();
//		System.out.println("Estado a comprobar: " + env.toString());
//		System.out.println("IsFinalState: " + htp.isFinalState(env));
//		
//	}
}